﻿using System;
using System.ComponentModel;
using System.IO;
using System.Windows;
using System.Windows.Input;
using Microsoft.Win32;
using WhiteFlow.Core.Caching;
using WhiteFlow.Core.Xml;
using WhiteFlow.DevTrackingTool.UI.Entities;
using WhiteFlow.DevTrackingTool.UI.Events;
using WhiteFlow.DevTrackingTool.UI.Models;
using WhiteFlow.DevTrackingTool.UI.Models.Cache;
using WhiteFlow.Wpf.Common.Commands;
using WhiteFlow.Wpf.Common.Mvvm.ViewModel;
using WhiteFlow.Wpf.Controls.Windows;

namespace WhiteFlow.DevTrackingTool.UI.ViewModels
{
    /// <summary>
    /// The ViewModel that manages and manipulates the main view.
    /// </summary>
    public class MainViewModel : ViewModelBase
    {
        #region Constants

        public const string WorksheetsExtensionFilter = "DWS Files (*.dws) | *.dws";

        public const string IsBackstageOpenPropertyName = "IsBackstageOpen";

        public const string CurrentBackstageTabPropertyName = "CurrentBackstageTab";

        public const string BackstageRecentTabViewModelPropertyName = "BackstageRecentTabViewModel";

        public const string WorksheetViewModelPropertyName = "WorksheetViewModel";

        public const string WorksheetCommandBarVisibilityPropertyName = "WorksheetCommandBarVisibility";

        public const string BackstageNewDocumentNamePropertyName = "BackstageNewDocumentName";

        #endregion

        #region Fields

        private bool isBackstageOpen;

        private BackstageTab currentBackstageTab;

        private BackstageRecentTabViewModel backstageRecentTabViewModel;

        private WorksheetViewModel worksheetViewModel;

        private Visibility? worksheetCommandBarVisibility;

        private ICommand createNewWorksheetCommand;

        private string backstageNewDocumentName;
        
        private ICommand openWorksheetCommand;

        private ICommand saveActiveWorksheetCommand;

        private ICommand saveActiveWorksheetAsCommand;
        
        private ICommand closeActiveWorksheetCommand;
        
        private ICommand exitCommand;

        private string initialDirectory;

        #endregion

        #region Properties

        public bool IsBackstageOpen
        {
            get { return isBackstageOpen; }
            set
            {
                isBackstageOpen = value;
                OnPropertyChanged(IsBackstageOpenPropertyName);
            }
        }

        public BackstageTab CurrentBackstageTab
        {
            get { return currentBackstageTab; }
            set
            {
                currentBackstageTab = value;
                OnPropertyChanged(CurrentBackstageTabPropertyName);
            }
        }

        public string BackstageNewDocumentName
        {
            get { return backstageNewDocumentName; }
            set
            {
                backstageNewDocumentName = value;
                OnPropertyChanged(BackstageNewDocumentNamePropertyName);
            }
        }

        public BackstageRecentTabViewModel BackstageRecentTabViewModel
        {
            get
            {
                if (backstageRecentTabViewModel == null)
                    backstageRecentTabViewModel = new BackstageRecentTabViewModel();

                return backstageRecentTabViewModel;
            }
            set
            {
                backstageRecentTabViewModel = value;
                OnPropertyChanged(BackstageRecentTabViewModelPropertyName);
            }
        }

        public WorksheetViewModel WorksheetViewModel
        {
            get { return worksheetViewModel; }
            set
            {
                worksheetViewModel = value;
                OnPropertyChanged(WorksheetViewModelPropertyName);

                if (value == null)
                {
                    WorksheetCommandBarVisibility = Visibility.Collapsed;
                    CurrentBackstageTab = BackstageTab.Backstage;
                    IsBackstageOpen = true;
                }
                else
                {
                    WorksheetCommandBarVisibility = Visibility.Visible;
                    CurrentBackstageTab = BackstageTab.Worksheet;
                    IsBackstageOpen = false;
                }
            }
        }

        public Visibility WorksheetCommandBarVisibility
        {
            get
            {
                if (worksheetCommandBarVisibility.HasValue)
                    return worksheetCommandBarVisibility.Value;
                else
                    return Visibility.Collapsed;
            }
            set
            {
                worksheetCommandBarVisibility = value;
                OnPropertyChanged(WorksheetCommandBarVisibilityPropertyName);
            }
        }

        #endregion

        #region Commands

        public ICommand CreateNewWorksheetCommand
        {
            get
            {
                if (createNewWorksheetCommand == null)
                {
                    createNewWorksheetCommand = new DelegateCommand(
                        NewWorksheet,
                        delegate() { return true; });
                }

                return createNewWorksheetCommand;
            }
        }

        public ICommand OpenWorksheetCommand
        {
            get
            {
                if (openWorksheetCommand == null)
                {
                    openWorksheetCommand = new DelegateCommand(
                        OpenWorksheet,
                        delegate() { return true; });
                }

                return openWorksheetCommand;
            }
        }

        public ICommand SaveActiveWorksheetCommand
        {
            get
            {
                if (saveActiveWorksheetCommand == null)
                {
                    saveActiveWorksheetCommand = new DelegateCommand(
                        SaveActiveWorksheet,
                        CanSaveWorksheet);
                }

                return saveActiveWorksheetCommand;
            }
        }

        public ICommand SaveActiveWorksheetAsCommand
        {
            get
            {
                if (saveActiveWorksheetAsCommand == null)
                {
                    saveActiveWorksheetAsCommand = new DelegateCommand(
                        SaveActiveWorksheetAs,
                        CanSaveWorksheetAs);
                }

                return saveActiveWorksheetAsCommand;
            }
        }

        public ICommand CloseActiveWorksheetCommand
        {
            get
            {
                if (closeActiveWorksheetCommand == null)
                {
                    closeActiveWorksheetCommand = new DelegateCommand<CancelEventArgs>(
                        CloseActiveWorksheet,
                        CanCloseWorksheet);
                }

                return closeActiveWorksheetCommand;
            }
        }

        public ICommand ExitCommand
        {
            get
            {
                if (exitCommand == null)
                {
                    exitCommand = new DelegateCommand<CancelEventArgs>(
                        ExitApplication, 
                        delegate(CancelEventArgs e) { return true; });
                }

                return exitCommand;
            }
        }

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="MainViewModel"/> class.
        /// </summary>
        public MainViewModel()
        {
            CurrentBackstageTab = BackstageTab.Backstage;
            IsBackstageOpen = true;

            App.EventAggregator.GetEvent<QueryRecentWorksheetOpenEvent>().Subscribe(OpenRecentWorksheet);
            App.EventAggregator.GetEvent<QueryOpenWorksheetFromRecentLocationEvent>().Subscribe(OpenFromRecentLocation);
        }

        #endregion

        #region Private Methods

        private void NewWorksheet()
        {
            CancelEventArgs e = null;

            if (CanCloseWorksheet())
            {
                e = new CancelEventArgs();
                e.Cancel = false;

                CloseWorksheet(e);
            }

            if (e == null || !e.Cancel)
            {
                InitWorksheet();
            }
        }

        private void OpenWorksheet()
        {
            OpenFileDialog dialog = new OpenFileDialog();
            dialog.Filter = WorksheetsExtensionFilter;
            
            if (initialDirectory != null)
                dialog.InitialDirectory = initialDirectory;
            else
            {
                string myComputerFolderPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);

                if (!String.IsNullOrEmpty(myComputerFolderPath))
                    dialog.InitialDirectory = myComputerFolderPath;
            }

            bool? result = dialog.ShowDialog();

            if (result.HasValue && result.Value)
            {
                if (CanCloseWorksheet())
                {
                    CloseWorksheet();
                }

                OpenDesiredFile(dialog.FileName);
            }
        }

        private void OpenRecentWorksheet(RecentWorksheet recentWorksheet)
        {
            if (!File.Exists(recentWorksheet.FullPath))
            {
                MessageBoxResult result = ModalDialog.ShowMessage(
                    "Dev Tracking Tool",
                    "The requested item no longer exists at the specified location.\r\nDo you want to remove it from list?",
                    MessageBoxButton.YesNoCancel,
                    MessageBoxImage.Question);

                switch (result)
                {
                    case MessageBoxResult.Yes:
                        AppCacheHelper.DeleteEntry<RecentWorksheet, DevTrackingToolCache>(DevTrackingToolCache.RecentWorksheetsPropertyName, recentWorksheet);
                        BackstageRecentTabViewModel.RefreshData();
                        break;
                }
            }
            else
            {
                OpenDesiredFile(recentWorksheet.FullPath);
            }
        }

        private void OpenFromRecentLocation(string recentLocation)
        {
            if (!Directory.Exists(recentLocation))
            {
                ModalDialog.ShowMessage(
                    "Dev Tracking Tool",
                    "This location no longer exists.",
                    MessageBoxButton.OK,
                    MessageBoxImage.Information);
            }
            else
            {
                initialDirectory = recentLocation;
                OpenWorksheet();
            }
        }

        private void CloseWorksheet(CancelEventArgs e = null)
        {
            if (WorksheetViewModel.Worksheet.IsDirty)
            {
                CurrentBackstageTab = BackstageTab.Worksheet;

                string message =
                    String.Format("Do you want to save worksheet \"{0}\" before closing it?", WorksheetViewModel.Worksheet.Title);

                MessageBoxResult result = ModalDialog.ShowMessage(
                    "Dev Tracking Tool",
                    message,
                    MessageBoxButton.YesNoCancel,
                    MessageBoxImage.Question);

                bool mustClose = true;

                switch (result)
                {
                    case MessageBoxResult.Yes:
                        SaveActiveWorksheet();
                        break;
                    case MessageBoxResult.Cancel:
                        mustClose = false;
                        if (e != null) e.Cancel = true;
                        break;
                }

                if (mustClose)
                {
                    WorksheetViewModel = null;
                }
            }
            else
            {
                WorksheetViewModel = null;
            }
        }

        private void SaveActiveWorksheet()
        {
            TrackingWorksheet worksheet = WorksheetViewModel.Worksheet;

            if (!String.IsNullOrEmpty(worksheet.PhysicalPath))
            {
                XmlHelper.SaveXmlEntity<TrackingWorksheet>(worksheet, worksheet.PhysicalPath);
                worksheet.IsDirty = false;

                RecentWorksheet recentWorksheet = new RecentWorksheet(worksheet.PhysicalPath);
                AppCacheHelper.AddEntry<RecentWorksheet, DevTrackingToolCache>(DevTrackingToolCache.RecentWorksheetsPropertyName, recentWorksheet);
            }
            else
            {
                SaveActiveWorksheetAs();
            }

            BackstageRecentTabViewModel.RefreshData();
        }

        private bool CanSaveWorksheet()
        {
            return (WorksheetViewModel != null && WorksheetViewModel.Worksheet.IsDirty);
        }

        private void SaveActiveWorksheetAs()
        {
            TrackingWorksheet worksheet = WorksheetViewModel.Worksheet;

            SaveFileDialog dialog = new SaveFileDialog();

            if (!String.IsNullOrEmpty(worksheet.PhysicalPath))
                dialog.FileName = worksheet.PhysicalPath;

            dialog.Filter = WorksheetsExtensionFilter;
            bool? result = dialog.ShowDialog();

            if (result.HasValue && result.Value)
            {
                worksheet.PhysicalPath = dialog.FileName;
                worksheet.Title = System.IO.Path.GetFileNameWithoutExtension(worksheet.PhysicalPath);

                XmlHelper.SaveXmlEntity<TrackingWorksheet>(worksheet, dialog.FileName);
                worksheet.IsDirty = false;

                RecentWorksheet recentWorksheet = new RecentWorksheet(worksheet.PhysicalPath);
                AppCacheHelper.AddEntry<RecentWorksheet, DevTrackingToolCache>(DevTrackingToolCache.RecentWorksheetsPropertyName, recentWorksheet);
            }
        }
        
        private bool CanSaveWorksheetAs()
        {
            return (WorksheetViewModel != null);
        }

        private void CloseActiveWorksheet(CancelEventArgs e = null)
        {
            CloseWorksheet();
        }

        private bool CanCloseWorksheet(CancelEventArgs e = null)
        {
            return (WorksheetViewModel != null);
        }

        private void InitWorksheet()
        {
            CurrentBackstageTab = BackstageTab.Worksheet;
            IsBackstageOpen = false;

            WorksheetViewModel = new WorksheetViewModel();
            WorksheetViewModel.Worksheet.Title = String.IsNullOrEmpty(BackstageNewDocumentName) ? "New Worksheet" : BackstageNewDocumentName;
            BackstageNewDocumentName = null;
            WorksheetViewModel.Worksheet.IsDirty = true;

            // Reset date to current day.
            WorksheetViewModel.SelectedDay = DateTime.Now.Date;
        }

        private void OpenDesiredFile(string fileName)
        {
            if (!String.IsNullOrEmpty(fileName))
            {
                CurrentBackstageTab = BackstageTab.Worksheet;

                if (IsWorksheetAlreadyOpen(fileName))
                {
                    // The specified worksheet is already opened.
                }
                else
                {
                    WorksheetViewModel = new WorksheetViewModel();
                    WorksheetViewModel.DeactivateWorksheetChangeNotification();

                    string worksheetTitle = System.IO.Path.GetFileNameWithoutExtension(fileName);

                    TrackingWorksheet worksheet = XmlHelper.LoadXmlEntity<TrackingWorksheet>(fileName);

                    if (worksheet == null)
                    {
                        ModalDialog.ShowMessage(
                            "Dev Tracking Tool",
                            "Unable to open the specified file.",
                            MessageBoxButton.OK,
                            MessageBoxImage.Error);
                    }
                    else
                    {
                        WorksheetViewModel.Worksheet = worksheet;
                        WorksheetViewModel.Worksheet.PhysicalPath = fileName;
                        WorksheetViewModel.Worksheet.Title = worksheetTitle;

                        #region Fix for serialization issue on collections

                        if (WorksheetViewModel.Worksheet.Customers.Count == 0)
                            WorksheetViewModel.Worksheet.Customers = null;

                        if (WorksheetViewModel.Worksheet.Projects.Count == 0)
                            WorksheetViewModel.Worksheet.Projects = null;

                        #endregion

                        #region Set owners for TrackingDay/ExecutedTasks instances

                        WorksheetViewModel.Worksheet.WorksheetSettings.SetOwner(WorksheetViewModel.Worksheet);
                        WorksheetViewModel.Worksheet.UpdateOwners();

                        #endregion

                        // Bring into view the "Tasks List" tab, that's the starting tab for a worksheet just
                        // opened or created.
                        WorksheetViewModel.SelectedWorksheetTab = 0;
                        // Bring into view the current day as a new worksheet is being opened.
                        WorksheetViewModel.SelectedDay = DateTime.Now.Date;

                        // Add current worksheet to cache, if it is not present yet.
                        RecentWorksheet recentWorksheet = new RecentWorksheet(fileName);
                        AppCacheHelper.AddEntry<RecentWorksheet, DevTrackingToolCache>(DevTrackingToolCache.RecentWorksheetsPropertyName, recentWorksheet);

                        BackstageRecentTabViewModel.RefreshData();
                    }

                    WorksheetViewModel.ActivateWorksheetChangeNotification();
                }
            }
        }

        private bool IsWorksheetAlreadyOpen(string filename)
        {
            return (
                WorksheetViewModel != null &&
                WorksheetViewModel.Worksheet.PhysicalPath != null &&
                WorksheetViewModel.Worksheet.PhysicalPath.Equals(filename));
        }

        private void ExitApplication(CancelEventArgs e = null)
        {
            if (CanCloseWorksheet(e))
            {
                CloseWorksheet(e);
            }
            else
            {
                if (e == null)
                {
                    Application.Current.Shutdown();
                }
            }
        }

        #endregion
    }
}